#include "header.hpp"
using namespace std;

//Callable object wrapper and binder
//Binder: std::bind uses to bind the callable object with its parameters

void output1(int x, int y){
    cout << x << " " << y << endl;
}

void output_add(int x, int y){
    cout << "x: " << x << ", y:" << y
         << ", x + y = " << x + y << endl;
}

void testFunc(int x, int y, const function<void(int, int)>& f){
    if(x % 2 == 0){
        f(x, y);
    }
}

void test7(){
    //Simple instance
    bind(output1, 1, 2);
    bind(output1, placeholders::_1, 2)(10);
    bind(output1, 2, placeholders::_1)(10);

    bind(output1, 2, placeholders::_2)(10, 20); //2 20


    //Usage of callable object binder
    //Bind to normal function
    for(int i = 0; i < 10; ++i){
        auto f1 = bind(output_add, i + 100, i + 200);
        testFunc(i, i, f1);

        auto f2 = bind(output_add, placeholders::_1, placeholders::_2);
        testFunc(i, i, f2);

        cout << endl;
    }


    //Bind to member function or member variable
    class Test{
    public:
        void output(int x, int y){
            cout << "x: " << x << ", y: " << y << endl;
        }

        int m_number = 100;
    };

    Test t;
    function<void(int)> f3 = bind(&Test::output, &t, 520, placeholders::_1);
    f3(1314);

    function<int&(void)> f4 = bind(&Test::m_number, &t);
    cout << f4() << endl;
    f4() = 666;
    cout << f4() << endl;
}
